package com.woniu.cms.goods.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.cms.goods.core.entity.GoodsGetbillMaterial;
import com.woniu.cms.goods.core.entity.GoodsOutbill;
import com.woniu.cms.goods.core.entity.GoodsOutbillMaterial;
import com.woniu.cms.goods.core.exception.Asserts;
import com.woniu.cms.goods.core.exception.BusinessException;
import com.woniu.cms.goods.core.mapper.GoodsOutbillMapper;
import com.woniu.cms.goods.core.service.IGoodsGetbillMaterialService;
import com.woniu.cms.goods.core.service.IGoodsOutbillMaterialService;
import com.woniu.cms.goods.core.service.IGoodsOutbillService;
import com.woniu.cms.goods.core.util.AspectsMsg;
import com.woniu.common.api.Result;
import com.woniu.common.api.status.Impl.BusinessCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 领料单表 服务实现类
 * </p>
 *
 * @author romantic sheep
 * @since 2022-09-18
 */
@Service
public class GoodsOutbillServiceImpl extends ServiceImpl<GoodsOutbillMapper, GoodsOutbill> implements IGoodsOutbillService {
    @Autowired
    private IGoodsOutbillMaterialService outbillMaterialService;
    @Autowired
    private IGoodsGetbillMaterialService getbillMaterialService;
    @Override
    @Transactional( propagation = Propagation.REQUIRED  //必须添加事务
            ,timeout = -1         //设置连接永不超时
            ,rollbackFor = {BusinessException.class}  // 抛出异常时进行回滚
            ,isolation = Isolation.DEFAULT                   // 使用数据库的隔离级别
    )
    public Result addOutbill(GoodsOutbill outbill, List<GoodsOutbillMaterial> list) {
        if (ObjectUtils.isEmpty(outbill)){
            return Result.error("请输入必填数据");
        }
        //先保存出库单主表，保存失败抛出异常，事务回滚
        boolean save = this.save(outbill);
        System.out.println("save = " + save);
        if (!save){
            Asserts.failed(AspectsMsg.SAVE_EXCEPTION);
        }
        //查询出库单主表id，填入材料信息表外键
        LambdaQueryWrapper<GoodsOutbill> qw = Wrappers.lambdaQuery();
        qw.eq(GoodsOutbill::getOutbillCode,outbill.getOutbillCode());
        GoodsOutbill outbill1 = this.getOne(qw);
        List<GoodsOutbillMaterial> collect = list.stream().map(e -> {
            e.setOutbillId(outbill1.getId());
            return e;
        }).collect(Collectors.toList());
        //保存材料信息表。保存失败则事务回滚
        boolean b = outbillMaterialService.saveBatch(collect);
        System.out.println("b = " + b);
        if (!b){
            Asserts.failed(AspectsMsg.SAVE_EXCEPTION);
        }
        return Result.ok(BusinessCode.ADD_SUCCESS);
    }
    @Override
    @Transactional( propagation = Propagation.REQUIRED  //必须添加事务
            ,timeout = -1         //设置连接永不超时
            ,rollbackFor = {BusinessException.class}  // 抛出异常时进行回滚
            ,isolation = Isolation.DEFAULT                   // 使用数据库的隔离级别
    )
    public Result deleteOutbill(Integer id, Integer status) {
        GoodsOutbill goodsOutbill = this.getById(id);
        if (ObjectUtils.isEmpty(goodsOutbill)){
            return Result.error(BusinessCode.REMOVE_FAIL);
        }
        if (goodsOutbill.getStatus()!=0&&goodsOutbill.getStatus()!=3){
            return Result.error("单据已提交无法删除");
        }
        //先删除出库单主表，删除失败则抛出异常，事务回滚。
        boolean b = this.removeById(id);
        if (!b){
            Asserts.failed(AspectsMsg.DELETE_EXCEPTION);
        }
        LambdaUpdateWrapper<GoodsOutbillMaterial> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(GoodsOutbillMaterial::getOutbillId,id);
        //再删除出库单材料明细表，删除失败则事务回滚
        boolean remove = outbillMaterialService.remove(updateWrapper);
        if (!remove){
            Asserts.failed(AspectsMsg.DELETE_EXCEPTION);
        }
        return Result.ok(BusinessCode.REMOVE_SUCCESS);
    }

    @Override
    @Transactional( propagation = Propagation.REQUIRED  //必须添加事务
            ,timeout = -1         //设置连接永不超时
            ,rollbackFor = {BusinessException.class}  // 抛出异常时进行回滚
            ,isolation = Isolation.DEFAULT                   // 使用数据库的隔离级别
    )
    public Result updateOutbill(GoodsOutbill outbill, List<GoodsOutbillMaterial> list) {
        if (outbill.getStatus()!=0&&outbill.getStatus()!=3){
            return Result.error(BusinessCode.MODIFY_FAIL);
        }
        //先修改出库单主表，修改失败则抛出异常事务回滚
        boolean b = this.updateById(outbill);
        if (!b){
            Asserts.failed(AspectsMsg.UPDATE_EXCEPTION);
        }
        //再修改出库单材料表，修改失败则抛出异常事务回滚
        boolean b1 = outbillMaterialService.updateBatchById(list);
        if (!b1){
            Asserts.failed(AspectsMsg.UPDATE_EXCEPTION);
        }
        return Result.ok(BusinessCode.MODIFY_SUCCESS);
    }

    @Override
    @Transactional( propagation = Propagation.REQUIRED  //必须添加事务
            ,timeout = -1         //设置连接永不超时
            ,rollbackFor = {BusinessException.class}  // 抛出异常时进行回滚
            ,isolation = Isolation.DEFAULT                   // 使用数据库的隔离级别
    )
    public Result commitOutbill(GoodsOutbill outbill, List<GoodsOutbillMaterial> list) {
        if (outbill.getStatus()==2){
            return Result.error("单据已提交，无法重复提交");
        }
        //使用stream将材料表对应的入库材料明细表id取出
        List<Integer> ids = list.stream().map(e -> e.getGetbillMaterialId()).collect(Collectors.toList());
        //根据id查询所有对应的入库单材料明细，一个出库单只能领用同一材料一次，所以一一对应。
        LambdaQueryWrapper<GoodsGetbillMaterial> qw = Wrappers.lambdaQuery();
        qw.in(GoodsGetbillMaterial::getId,ids);
        List<GoodsGetbillMaterial> getbillMaterials = getbillMaterialService.list(qw);
        //对入库、出库材料明细进行排序。排序后下标一一对应
        list.sort(new Comparator<GoodsOutbillMaterial>() {
            @Override
            public int compare(GoodsOutbillMaterial o1, GoodsOutbillMaterial o2) {
                return o1.getGetbillMaterialId()-o2.getGetbillMaterialId();
            }
        });
        getbillMaterials.sort(new Comparator<GoodsGetbillMaterial>() {
            @Override
            public int compare(GoodsGetbillMaterial o1, GoodsGetbillMaterial o2) {
                return o1.getId()-o2.getId();
            }
        });
        //循环修改库存数量。
        for (int i=0;i<list.size();i++){
            BigDecimal outbillNum = list.get(i).getOutbillNum();
            BigDecimal residueNum = getbillMaterials.get(i).getResidueNum();
            if (outbillNum.compareTo(residueNum)==1){
                return Result.error("提交失败，材料库存不足");
            }
        }
        //修改出库单状态为已提交
        outbill.setStatus(1);
        //初始化未结算数量=领料数量
        List<GoodsOutbillMaterial> collect1 = list.stream().map(e -> {
            e.setRealNum(e.getOutbillNum());
            return e;
        }).collect(Collectors.toList());
        //保存出库单主表,保存失败则抛出异常事务回滚
        boolean b = this.updateById(outbill);
        if (!b){
            Asserts.failed(AspectsMsg.UPDATE_EXCEPTION);
        }
        //保存出库单材料明细表。保存失败则抛出异常事务回滚
        boolean b1 = outbillMaterialService.updateBatchById(collect1);
        if (!b1){
            Asserts.failed(AspectsMsg.UPDATE_EXCEPTION);
        }
        return Result.ok("单据提交成功");
    }


}
